package cn.tannn.cat.file.sdk.core.local;

import cn.tannn.cat.file.sdk.OssOperateAPI;
import cn.tannn.cat.file.sdk.api.UploadFile;
import cn.tannn.cat.file.sdk.bean.FileIndex;
import cn.tannn.cat.file.sdk.bean.FileStorage;
import cn.tannn.cat.file.sdk.config.LocalConfig;
import cn.tannn.cat.file.sdk.constants.OSSConstants;
import cn.tannn.cat.file.sdk.exception.FileException;
import cn.tannn.cat.file.sdk.utils.AboutFileUtil;
import cn.tannn.cat.file.sdk.utils.FileUtils;
import cn.tannn.cat.file.sdk.utils.ResponseFile;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.Objects;


/**
 * 本地撒上传
 *
 * @author tn
 * @version 1
 * @date 2022-04-01 14:35
 */
@Service
@Slf4j
public class LocalOperate implements OssOperateAPI {

    public static final String SPIRIT = "/";

    @Value("${server.port:8080}")
    private int serverPort;

    @Value("${server.servlet.context-path:/}")
    private String serverName;

    @Value("${server.servlet.context-path:/}")
    private String prefix;


    @Override
    public FileIndex uploadFile(UploadFile upload, FileStorage storage) throws IOException {
        LocalConfig localConfig = storage.getConfig().toJavaObject(LocalConfig.class);

        MultipartFile file = upload.getFile();
        // getOriginalFilename方法获取文件名(带后缀)
        String originalName = file.getOriginalFilename();
        if (originalName == null) {
            throw FileException.specialMessage("文件有问题，OriginalFilename 不允许为空");
        }
        // 新文件名
        String freshName;
        // 文件类型后缀 如 jpg png
        String suffixDot = AboutFileUtil.getFileSuffixDot(originalName);
        if (StringUtils.isNotBlank(upload.getFileName())) {
            freshName = upload.getFileName().trim() + suffixDot;
        } else {
            freshName = LocalDirverUtil.encrypt2MD5(originalName) + suffixDot;
        }
        // 子目录
        String childFolder = Objects.isNull(upload.getChildFolder()) ? "" : upload.getChildFolder();
        String diskPathLast;
        if (localConfig.getSharding()) {
            // 块目录。文件自动切分目录存储防止单文件存储数据太多
            String subdir = FileUtils.getSubdir(freshName);
            // 子目录+ 文件名
            diskPathLast = childFolder + subdir + OSSConstants.PATH_SEPARATOR + freshName;
        } else {
            diskPathLast = childFolder + freshName;
        }

        String diskPathBucket = upload.getBucket() + OSSConstants.PATH_SEPARATOR + diskPathLast;
        // 文件URL后缀
        String urlSuffix = diskPathBucket;
        // 文件存储目录
        File dest = new File(localConfig.getUploadDir() + OSSConstants.PATH_SEPARATOR + urlSuffix);
        // 判断文件所在目录是否存在，如果不存在就创建对应的目录
        if (!dest.getParentFile().exists()) {
            dest.getParentFile().mkdirs();
        }
        // 将文件存放到对应的目录下，如果上传重复的文件不会报错，后上传的文件会覆盖已上传的文件
        file.transferTo(dest);
        String contextPath = LocalDirverUtil.contextPath(localConfig.getContextPath());
        if (StringUtils.isNotBlank(contextPath)) {
            urlSuffix = contextPath.substring(0, contextPath.lastIndexOf(SPIRIT) + 1) + urlSuffix;
        }
        // 自动处理 接口context-path
        if (!"/".equals(prefix)) {
            urlSuffix = prefix + urlSuffix;
        }
        String url = getBrowserUrl(localConfig.getBrowseUrl()) + urlSuffix;
        FileIndex fileStorage = new FileIndex();
        fileStorage.setStorageId(storage.getId());
        fileStorage.setStorage(storage.getStorage());
        fileStorage.setOriginalName(originalName);
        fileStorage.setFreshName(freshName);
        // 存储在设备里的真实路径
        String diskPath = localConfig.getUploadDir() + SPIRIT + diskPathBucket;
        fileStorage.setSubPath(diskPathLast);
        fileStorage.setPath(diskPath);
        fileStorage.setUrl(url);
        fileStorage.setUrlSuffix(urlSuffix);
        fileStorage.setBucket(upload.getBucket());
        fileStorage.setBucketPath(OSSConstants.PATH_SEPARATOR + diskPathBucket);
        fileStorage.setType(upload.getFile().getContentType());
        fileStorage.setSizeUnit(AboutFileUtil.getFileSizeUnit(upload.getFile().getSize()));
        fileStorage.setSize(upload.getFile().getSize());
        return fileStorage;

    }


    @Override
    public boolean removeFile(FileIndex index) {
        try {
            File file = new File(index.getPath());
            if (file.exists()) {
                return file.delete();
            } else {
                log.warn("文件不存在：index id : {} , URL: {}", index.getId(), index.getUrl());
                return true;
            }
        } catch (Exception e) {
            log.error("文件删除失败：index id : {} , URL: {}", index.getId(), index.getUrl(), e);
            throw FileException.specialMessage("文件删除失败");
        }

    }


    @Override
    public void downloadFile(HttpServletResponse response, FileIndex index) {
        File file = new File(index.getPath());
        try (InputStream in = Files.newInputStream(file.toPath())) {
            HttpServletResponse downResponse = ResponseFile.fileResponse(response, file);
            IOUtils.copy(in, downResponse.getOutputStream());
        } catch (Exception e) {
            log.error("下载文件失败：index id : {} , URL: {}", index.getId(), index.getUrl(), e);
        }
    }


    /**
     * 获取浏览地址前缀
     *
     * @param browseUrl browseUrl
     * @return url地址
     */
    private String getBrowserUrl(String browseUrl) {
        if (StringUtils.isBlank(browseUrl)) {
            if (SPIRIT.equals(serverName)) {
                serverName = "";
            }
            browseUrl = "http://" + LocalDirverUtil.getRealIp() + ":" + serverPort + serverName;
        }
        return browseUrl;
    }
}
